home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Visual Database / Visual BASIC 5.0 (Ent. Edition) / Vb5ent Extractor.EXE / VB / SAMPLES / PGUIDE / PROGWOB / PWOFRIEN.BAS < prev    next >
Encoding:
BASIC Source File  |  1996-11-26  |  10.0 KB  |  338 lines

  1. Attribute VB_Name = "modFriends"
  2. Option Explicit
  3. ' Constants for debug functions.
  4. Global Const DEBUGTOKEN_DebugID = 1
  5. Global Const DEBUGTOKEN_ClassName = 2
  6.  
  7. ' The user-defined type used by the
  8. '   Friend member demo.
  9. Public Type udtDEMO
  10.     intA As Integer
  11.     lngB As Long
  12.     strC As String
  13. End Type
  14.  
  15. ' timeGetTime is used by the Implements
  16. ' -----------       demo, and by the
  17. '   object lifetime debug code in this
  18. '   module.
  19. Declare Function timeGetTime Lib "winmm.dll" () As Long
  20.  
  21. ' Storage for the global collection
  22. '   for debugging object lifetimes.
  23. '   Used by DebugInit, DebugTerm,
  24. '   and DebugShow procedures (below).
  25. Private mcolDebug As New Collection
  26.  
  27. '         DEBUGGING PROCEDURES
  28. '
  29. ' DebugInit
  30. ' DebugTerm
  31. ' DebugShow
  32. '
  33. ' All objects implement the IDebug
  34. '   interface, and support it by
  35. '   calling DebugInit(Me) in their
  36. '   Initialize events, and DebugTerm Me
  37. '   in their Terminate events.  You can
  38. '   use DebugShow in the Immediate window
  39. '   to list an active object, all active
  40. '   objects, or all objects of a class.
  41. '
  42. ' All of the objects in this project are
  43. '   set up to use these functions.
  44. '
  45. ' -------------------------------------
  46. ' DebugInit is called by each object,
  47. ' ---------     in its Initialize event.
  48. '   DebugInit adds a debug string for the
  49. '   object to the global collection, and
  50. '   returns a unique DebugID for the
  51. '   object. The method optionally shows
  52. '   the debug string in the Immediate
  53. '   window (default is True).
  54. '
  55. Public Function DebugInit(ByVal obj As Object, _
  56.         Optional ByVal ShowImmediate As Boolean = True) As Long
  57.     Dim lngDebugID As Long
  58.     Dim strDebug As String
  59.     
  60.     ' Get a unique ID number.
  61.     lngDebugID = GetDebugID
  62.     ' The debug string kept for each
  63.     '   object shows the DebugID, the
  64.     '   class name of the object, and
  65.     '   the time it was initialized
  66.     '   (number of seconds since the
  67.     '   first debug object was created,
  68.     '   expressed as a Double, with the
  69.     '   milliseconds as the fractional
  70.     '   part).
  71.     strDebug = lngDebugID & " " _
  72.         & TypeName(obj) _
  73.         & " (created at " & DebugTime & ")"
  74.     '
  75.     ' Add the string to the collection,
  76.     '   using the unique ID as a key.
  77.     mcolDebug.Add strDebug, CStr(lngDebugID)
  78.     '
  79.     ' The default is to show the debug
  80.     '   string in the Immediate window.
  81.     If ShowImmediate Then Debug.Print strDebug
  82.     '
  83.     ' Return the DebugID.  The object must
  84.     '   store this as part of the
  85.     '   implementation of IDebug.
  86.     DebugInit = lngDebugID
  87. End Function
  88.  
  89. ' DebugTerm is called by each object,
  90. ' ---------     in its Terminate event.
  91. '   DebugTerm removes the object's
  92. '   debug string from the global
  93. '   collection, and optionally (default
  94. '   is True) shows the debug string in
  95. '   the Immediate window.
  96. '
  97. Public Sub DebugTerm(ByVal obj As Object, _
  98.         Optional ByVal ShowImmediate As Boolean = True)
  99.     
  100.     Dim idbg As IDebug
  101.     
  102.     On Error Resume Next
  103.     '
  104.     ' Get a reference to the object's
  105.     '   IDebug interface.
  106.     Set idbg = obj
  107.     If Err.Number <> 0 Then
  108.         MsgBox TypeName(obj) & " doesn't implement IDebug; can't record termination.", , "DebugTerm"
  109.         Exit Sub
  110.     End If
  111.     '
  112.     ' The default is to show the debug
  113.     '   string in the Immediate window.
  114.     If ShowImmediate Then Debug.Print _
  115.         mcolDebug(CStr(idbg.DebugID)) _
  116.         & " (Term at " & DebugTime & ")"
  117.     '
  118.     ' Remove the string from the
  119.     '   collection.
  120.     mcolDebug.Remove CStr(idbg.DebugID)
  121. End Sub
  122.  
  123. ' DebugShow displays the debug string(s)
  124. ' ---------     for the entire list of
  125. '   active objects, for all active objects
  126. '   of a class, or for a particular object.
  127. '   Call DebugShow from the Immediate
  128. '   window with no argument (lists all),
  129. '   a class name (lists all of that class),
  130. '   an object reference (lists that
  131. '   object), or the DebugID of an object
  132. '   (lists that object).
  133. '
  134. Public Sub DebugShow(Optional ByVal What As Variant)
  135.     Dim vnt As Variant
  136.     Dim idbg As IDebug
  137.     
  138.     On Error GoTo NoShow
  139.     ' If no argument is supplied, display
  140.     '   all active objects.  (It would be
  141.     '   useful to have an optional second
  142.     '   parameter Filename that would let
  143.     '   you dump this to a file; or perhaps
  144.     '   it should dump to the Clipboard.)
  145.     If IsMissing(What) Then
  146.         What = "<All>"
  147.         For Each vnt In mcolDebug
  148.             Debug.Print vnt
  149.         Next
  150.     '
  151.     ' If an object is supplied, use its
  152.     '   DebugID to look up its debug
  153.     '   string.
  154.     ElseIf IsObject(What) Then
  155.         On Error Resume Next
  156.         '
  157.         ' Get a reference to the object's
  158.         '   IDebug interface.
  159.         Set idbg = What
  160.         If Err.Number <> 0 Then
  161.             MsgBox TypeName(What) & " doesn't implement IDebug; can't show debug record.", , "DebugShow"
  162.             Exit Sub
  163.         End If
  164.         '
  165.         Debug.Print mcolDebug(CStr(idbg.DebugID))
  166.     '
  167.     ' If a number is supplied, assume it's
  168.     '   a DebugID and use it to look up
  169.     '   the string.
  170.     ElseIf IsNumeric(What) Then
  171.         Debug.Print mcolDebug(CStr(What))
  172.     '
  173.     ' If it's not a number, assume it's
  174.     '   a string containing the class
  175.     '   name; display all objects with
  176.     '   that class name.
  177.     Else
  178.         For Each vnt In mcolDebug
  179.             If What = GetDebugToken(vnt, DEBUGTOKEN_ClassName) Then
  180.                 Debug.Print vnt
  181.             End If
  182.         Next
  183.     End If
  184.     Exit Sub
  185.     
  186. NoShow:
  187.     If IsObject(What) Then
  188.         MsgBox "Unable to display information.  Is this object set up for debugging?", , "DebugShow"
  189.     Else
  190.         MsgBox "Unable to display information for " _
  191.             & What & ".  Is this object set up for debugging?", , "DebugShow"
  192.     End If
  193. End Sub
  194.  
  195. ' GetDebugString returns an object's
  196. ' --------------    string from the global
  197. '   collection.
  198. '
  199. Public Function GetDebugString(ByVal obj As Object) As String
  200.     Dim idbg As IDebug
  201.     
  202.     On Error Resume Next
  203.     '
  204.     ' Get a reference to the object's
  205.     '   IDebug interface.
  206.     Set idbg = obj
  207.     GetDebugString = mcolDebug(CStr(idbg.DebugID))
  208. End Function
  209.  
  210. ' GetDebugID is used to assign each object
  211. ' ----------    a unique ID number, for
  212. '   debugging purposes.
  213. Public Function GetDebugID() As Long
  214.     Static lngLastID As Long
  215.     lngLastID = lngLastID + 1
  216.     GetDebugID = lngLastID
  217. End Function
  218.  
  219. ' GetDebugToken parses the debug string
  220. ' -------------     for an object and
  221. '   returns the requested token.  Tokens
  222. '   are separated by single spaces.
  223. '   (1) DebugID
  224. '   (2) class name
  225. '
  226. ' There are other tokens, but they're
  227. '   kind of a jumble.
  228. '
  229. Public Function GetDebugToken( _
  230.         ByVal DebugString As String, _
  231.         ByVal TokenNumber As Integer) As String
  232.  
  233.     Dim inx1 As Long
  234.     Dim inx2 As Long
  235.     Dim ct As Integer
  236.     
  237.     If TokenNumber <= 0 Then
  238.         Err.Raise vbObjectError + 1060, , _
  239.             "Bad token number in GetDebugToken"
  240.     Else
  241.         inx2 = 1
  242.         For ct = 1 To TokenNumber
  243.             inx1 = inx2
  244.             inx2 = InStr(inx1, DebugString, " ")
  245.             If inx2 = 0 Then Exit For
  246.         Next
  247.         If inx2 = 0 Then
  248.             GetDebugToken = ""
  249.         Else
  250.             GetDebugToken = Mid$(DebugString, inx1 + 1, inx2 - inx1)
  251.         End If
  252.     End If
  253. End Function
  254.         
  255. ' DebugTime uses the timeGetTime API to
  256. ' ---------     get milliseconds since
  257. '   the computer was booted.  This is
  258. '   converted to a Double containing the
  259. '   number of seconds since the first
  260. '   debug object was created (s.mmm),
  261. '   using the first time this function
  262. '   was called as the base time.  (This
  263. '   makes the time values more useful
  264. '   than the raw number of milliseconds
  265. '   since the last boot, which (1) tends
  266. '   to be a very large number, and (2) can
  267. '   be negative, as explained below.)
  268. '
  269. Public Function DebugTime() As Double
  270.     Static timeBase As Double
  271.     Dim timeCurrent As Double
  272.     
  273.     If timeBase = 0 Then
  274.         ' Initialize the base time.  (The
  275.         '   loop allows for the fact that
  276.         '   the time returned by timeGetTime
  277.         '   can pass through zero again, if
  278.         '   the computer is left running
  279.         '   long enough.)
  280.         Do While timeBase = 0
  281.             timeBase = timeGetTime
  282.         Loop
  283.         '
  284.         ' The value returned by timeGetTime
  285.         '   can be negative (see note
  286.         '   below) if the computer has
  287.         '   been running long enough.
  288.         '   Correct for this.
  289.         If timeBase < 0 Then
  290.             timeBase = timeBase + 4294967296#
  291.         End If
  292.     End If
  293.     '
  294.     timeCurrent = timeGetTime
  295.     '
  296.     ' Correct for negative value, if
  297.     '   necessary.
  298.     If timeCurrent < 0 Then
  299.         timeCurrent = timeCurrent + 4294967296#
  300.     End If
  301.     '
  302.     ' Handle the case where timeGetTime
  303.     '   rolls over to zero.
  304.     If timeCurrent < timeBase Then
  305.         DebugTime = (timeCurrent + 4294967296# - timeBase) / 1000#
  306.     Else
  307.         DebugTime = (timeCurrent - timeBase) / 1000#
  308.     End If
  309. End Function
  310. ' ----------- timeGetTime -----------
  311. ' The number of milliseconds since
  312. '   last boot is an unsigned four-byte
  313. '   binary integer, which means it can
  314. '   get bigger than a Long can hold.
  315. '   When it passes the largest positive
  316. '   number a Long can hold, 2147483647,
  317. '   it appears to Basic as if the
  318. '   number has 'rolled over' and gone
  319. '   negative.  Once it has rolled over,
  320. '   it continues increasing -- moving
  321. '   from the largest negative number a
  322. '   Long can hold up to zero, and then
  323. '   into positive numbers again.
  324. '
  325. ' This creates a 'sawtooth' pattern,
  326. '   and it works just fine for time
  327. '   differences (which is what
  328. '   DebugTime is calculating), except
  329. '   for that awkward moment when the
  330. '   rollover happens.
  331. '
  332. ' DebugTime solves this problem by
  333. '   putting the number into a larger
  334. '   container -- a Double.  If the
  335. '   number is negative, it can be
  336. '   turned into the number it should
  337. '   have been by adding 4294967296.
  338.